//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: sspg
// 
// Create Date: 2018/07/12 13:41:30
// Design Name: 
// Module Name: irig_state
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description:  
//
//    Lock onto and track the IRIG-B "states" separated by mark signals.
//
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
module irig_state (
    input                       clk,
    input                       rst,
    input                       irig_d0,
    input                       irig_d1,
    input                       irig_mark,
    output  reg                 unlock,
    output  reg                 pps_gate, 
    output  reg                 ts_finish,
    output  reg [2:0]           ts_select,
    output  reg [4:0]           bit_idx,       // index of binary bit in the BCD digit
    output  reg [1:0]           digit_idx,     // index of digit (i.e. power of 10)
    output  reg                 bit_value
    );

// State machine states
localparam ST_UNLOCKED = 4'd0;
localparam ST_PRELOCK  = 4'b1;
localparam ST_START    = 4'd2;
localparam ST_SECOND   = 4'd3;
localparam ST_MINUTE   = 4'd4;
localparam ST_HOUR     = 4'd5;
localparam ST_DAY      = 4'd6;
localparam ST_DAY2     = 4'd7;
localparam ST_YEAR     = 4'd8;
localparam ST_UNUSED1  = 4'd9;
localparam ST_UNUSED2  = 4'd10;
localparam ST_SEC_DAY  = 4'd11;
localparam ST_SEC_DAY2 = 4'd12;

// Timestamp selection
localparam TS_SELECT_SECOND = 3'd1;
localparam TS_SELECT_MINUTE = 3'd2;
localparam TS_SELECT_HOUR = 3'd3;
localparam TS_SELECT_DAY = 3'd4;
localparam TS_SELECT_YEAR = 3'd5;
localparam TS_SELECT_SEC_DAY = 3'd6;

// Count of the IRIG bits within a state
reg [3:0]                       irig_cnt;

// PPS generation internal signal
// Output is registered version
reg                             pps_en;

// Current and next state machine state
reg [3:0]                       state;
reg [3:0]                       next_state;

// Registers
always @(posedge clk) begin
    if (rst) begin
        state <= ST_UNLOCKED;
        pps_gate <= 1'b0;
        irig_cnt <= 4'b0;
    end else begin
        state <= next_state;
        pps_gate <= pps_en;

        // Count the IRIG bits received between every MARK
        if (irig_mark)
            irig_cnt <= 4'b0;
        else 
            irig_cnt <= irig_cnt + (irig_d0 | irig_d1);
    end
end

// IRIG decoding state machine
always @(*) begin
    next_state = state;
    pps_en = 1'b0;
    ts_finish = 1'b0;
    ts_select = 3'b0;
    bit_idx = 4'b0;
    digit_idx = 2'b0;
    bit_value = 1'b0;
    unlock = 1'b0;
    case (state)
        ST_UNLOCKED: begin
            unlock = 1'b1;
            if (irig_mark)
                next_state = ST_PRELOCK;
        end
        ST_PRELOCK: begin
            unlock = 1'b1;
            if (irig_mark)
                next_state = ST_SECOND;
            else if (irig_d0 || irig_d1)
                next_state = ST_UNLOCKED;          
        end
        ST_START: begin              
            pps_en = 1'b1;
            if (irig_mark) begin
                next_state = ST_SECOND;
            end
        end
        ST_SECOND: begin
            ts_select = TS_SELECT_SECOND;
            bit_idx = (irig_cnt > 4'd4) ? irig_cnt-4'd5 : irig_cnt;
            digit_idx = (irig_cnt > 4'd4) ? 2'b1 : 2'b0;
            bit_value = irig_d1 && !(irig_cnt == 4'd4);                

            if (irig_mark) begin
                if(irig_cnt == 4'd8) begin
                    next_state = ST_MINUTE;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_MINUTE: begin
            ts_select = TS_SELECT_MINUTE;
            bit_idx = (irig_cnt > 4'd4) ? irig_cnt-4'd5 : irig_cnt;
            digit_idx = (irig_cnt > 4'd4) ? 2'b1 : 2'b0;
            bit_value = irig_d1 && !(irig_cnt == 4'd4) && !(irig_cnt == 4'd8);

            if (irig_mark) begin
                if(irig_cnt == 4'd9) begin
                    next_state = ST_HOUR;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end       
        ST_HOUR: begin
            ts_select = TS_SELECT_HOUR;
            bit_idx = (irig_cnt > 4'd4) ? irig_cnt-4'd5 : irig_cnt;
            digit_idx = (irig_cnt > 4'd4) ? 2'b1 : 2'b0;
            bit_value = irig_d1 && !(irig_cnt == 4'd4) && !(irig_cnt >= 4'd8);

            if (irig_mark) begin
                if(irig_cnt == 4'd9) begin
                    next_state = ST_DAY;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_DAY: begin
            ts_select = TS_SELECT_DAY;
            bit_idx = (irig_cnt > 4'd4) ? irig_cnt-4'd5 : irig_cnt;
            digit_idx = (irig_cnt > 4'd4) ? 2'd1 : 2'd0;
            bit_value = irig_d1 && !(irig_cnt == 4'd4);

            if (irig_mark) begin
                if(irig_cnt == 4'd9) begin
                    next_state = ST_DAY2;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_DAY2: begin
            ts_select = TS_SELECT_DAY;
            bit_idx = irig_cnt;
            digit_idx = 2'd2;
            bit_value = irig_d1 && !(irig_cnt > 4'd1);

            if (irig_mark) begin
                if(irig_cnt == 4'd9) begin
                    next_state = ST_YEAR;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_YEAR: begin
            ts_select = TS_SELECT_YEAR;
            bit_idx = (irig_cnt > 4'd4) ? irig_cnt-4'd5 : irig_cnt;
            digit_idx = (irig_cnt > 4'd4) ? 2'd1 : 2'd0;
            bit_value = irig_d1 && !(irig_cnt == 4'd4);

            if (irig_mark) begin
                if(irig_cnt == 4'd9) begin
                    next_state = ST_UNUSED1;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_UNUSED1: begin
            if (irig_mark) begin
               if(irig_cnt == 4'd9) begin
                    next_state = ST_UNUSED2;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_UNUSED2: begin
            if (irig_mark) begin
               if(irig_cnt == 4'd9) begin
                    next_state = ST_SEC_DAY;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_SEC_DAY: begin
            ts_select = TS_SELECT_SEC_DAY;
            bit_idx = irig_cnt;
            bit_value = irig_d1;
            if (irig_mark) begin
               if(irig_cnt == 4'd9) begin
                    next_state = ST_SEC_DAY2;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        ST_SEC_DAY2: begin
            ts_select = TS_SELECT_SEC_DAY;
            bit_idx = irig_cnt+5'd9;
            bit_value = irig_d1;
            if (irig_mark) begin
                if(irig_cnt == 4'd9) begin
                    next_state = ST_START;
                    pps_en = 1'b1;
                    ts_finish = 1'b1;
                end else begin
                    next_state = ST_UNLOCKED;
                end
            end
        end
        default: begin
            next_state = ST_UNLOCKED;
        end
    endcase
end
    
endmodule
